﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DO = ServerDataObject;
using DataLayer;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Configuration;

namespace BussinesLayer
{
    public class Storage
    {
        object lockObject = new object();
        public StorageDataContext DataContext
        {
            get
            {
                return new StorageDataContext { ObjectTrackingEnabled = false };
            }
        }

        public StorageDataContext EditableDataContext
        {
            get
            {
                return new StorageDataContext();
            }
        }

        CloudBlobContainer _blobContainer;
        public CloudBlobContainer BlobContainer
        {
            get
            {
                if (_blobContainer == null)
                {
                    lock (lockObject)
                    {
                        if (_blobContainer == null)
                        {
                            var connectionString = string.Format("DefaultEndpointsProtocol=http;AccountName={0};AccountKey={1}",
                                ConfigurationManager.AppSettings["storageUserName"],
                                ConfigurationManager.AppSettings["storageKey"]);
                            var cloudStorageAccount = CloudStorageAccount.Parse(connectionString);
                            var blobClient = cloudStorageAccount.CreateCloudBlobClient();
                            var blobContainer = blobClient.GetContainerReference("container");
                            blobContainer.CreateIfNotExist();
                            var containerPermissions = new BlobContainerPermissions();
                            containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
                            blobContainer.SetPermissions(containerPermissions);
                            _blobContainer = blobContainer;
                        }
                    }
                }
                return _blobContainer;
            }
        }

        public List<DO.ChallengeShort> GetChallengeList(DO.ChallengeFiler filter)
        {
            using (var dc = DataContext)
            {
                return dc.Challenges.Select(q => new DO.ChallengeShort
                {
                    Id = q.ID,
                    Name = q.Name,
                    CheckPointCount = q.CheckPoints.Count(),
                    Points = q.CheckPoints.Sum(p => p.Points)
                }).ToList();
            }
        }

        public DO.Challenge GetChallenge(Guid id)
        {
            using (var dc = DataContext)
            {
                var challenge = dc.Challenges
                    .Where(q => q.ID == id)
                    .Select(q => new DO.Challenge
                {
                    Id = q.ID,
                    Name = q.Name,
                    Description = q.Description,
                    MinScore = q.MinScore,
                    Points = q.Points
                }).SingleOrDefault();

                if (challenge != null)
                {
                    challenge.CheckPoints = new List<DO.CheckPoint>();
                    var points = dc.CheckPoints
                        .Where(q => q.ChallengeId == id)
                        .ToList();

                    points.ForEach(p => challenge.CheckPoints.Add(new DO.CheckPoint
                    {
                        Accuracy = p.Accuracy,
                        Address = p.Address,
                        Description = p.Description,
                        Id = p.ID,
                        Latitude = p.Latitude,
                        Longitude = p.Longitude,
                        Name = p.Name,
                        OtherLink = p.OtherLink,
                        Picture = p.Picture,
                        Points = p.Points,
                        WikiLink = p.WikiLink
                    }));
                }
                return challenge;
            }
        }

        private void AddChallenge(DO.SyncItem syncItem, StorageDataContext dc)
        {
            var data = syncItem.NewChallenge;
            var challenge = new Challenge()
            {
                ID = data.Id,
                Description = data.Description,
                Name = data.Name
            };
            dc.Challenges.InsertOnSubmit(challenge);
            var award = new Award
            {
                ChallengeId = challenge.ID,
                ID = Guid.NewGuid(),
                Name = "Challenge complite",
                WinPoints = data.CheckPoints.Sum(q => q.Points)
            };
            dc.Awards.InsertOnSubmit(award);

            foreach (var item in data.CheckPoints)
            {

                var point = new CheckPoint()
                {
                    ID = item.Id,
                    Accuracy = item.Accuracy,
                    Address = item.Address,
                    ChallengeId = challenge.ID,
                    Description = item.Description,
                    Latitude = item.Latitude,
                    Longitude = item.Longitude,
                    Name = item.Name,
                    OtherLink = item.OtherLink,
                    Points = item.Points,
                    WikiLink = item.WikiLink
                };
                if (item.Picture != null && item.Picture.Length > 0)
                {
                    var blob = BlobContainer.GetBlobReference(string.Format("cl_point_{0}", item.Id));
                    blob.UploadByteArray(item.Picture);
                    point.Picture = blob.Uri.ToString();
                }
                dc.CheckPoints.InsertOnSubmit(point);
            }
            dc.SubmitChanges();
        }

        public bool SyncChanges(DO.SyncChallenges syncData)
        {
            using (var dc = EditableDataContext)
            {
                foreach (var syncItem in syncData.Items.OrderBy(q => q.OrderNr))
                {
                    if (syncItem.ItemType == DO.SyncItemType.AddChallenge)
                    {
                        AddChallenge(syncItem, dc);
                    }
                    if (syncItem.ItemType == DO.SyncItemType.AddPerson)
                    {
                        AddPerson(syncItem, dc);
                    }
                    if (syncItem.ItemType == DO.SyncItemType.AddPersonAward)
                    {
                        AddPersonAward(syncItem, dc);
                    }
                    if (syncItem.ItemType == DO.SyncItemType.EditPerson)
                    {
                        UpdatePerson(syncItem, dc);
                    }
                }

                return true;
            }
        }

        private void UpdatePerson(DO.SyncItem syncItem, StorageDataContext dc)
        {
            var person = dc.Persons.Where(q => q.ID == syncItem.EditPerson.Id).SingleOrDefault();
            if (person != null)
            {
                person.Name = syncItem.EditPerson.Name;
                dc.SubmitChanges();
            }            
        }

        private void AddPerson(DO.SyncItem syncItem, StorageDataContext dc)
        {
            var newPerson = syncItem.NewPerson;
            var person = new Person()
            {
                ID = newPerson.Id,
                Name = newPerson.Name
            };
            dc.Persons.InsertOnSubmit(person);
            dc.SubmitChanges();
        }
        private void AddPersonAward(DO.SyncItem syncItem, StorageDataContext dc)
        {
            var newPersonAward = syncItem.AwardRequest;

            var award = dc.Awards.Where(q => q.ChallengeId == newPersonAward.ChallengeId).SingleOrDefault();
            if (award != null)
            {
                var personAward = new PersonAward()
                {
                    AwardId = award.ID,
                    Date = newPersonAward.Date,
                    PersonId = newPersonAward.PersonId,
                    Points = award.WinPoints
                };
                dc.PersonAwards.InsertOnSubmit(personAward);
                dc.SubmitChanges();
            }
        }

        public List<DO.PersonScore> GetPersonScore()
        {
            using (var dc = DataContext)
            {
                return dc.Persons.Select(q =>
                    new DO.PersonScore
                    {
                        Id = q.ID,
                        Name = q.Name,
                        Points = q.PersonAwards.Sum(t => t.Points)
                    }).ToList();
            }
        }
    }
}
